package com.farben.web.controller.aging;

import com.farben.common.core.controller.BaseController;
import com.farben.common.core.domain.AjaxResult;
import com.farben.common.utils.StringUtils;
import com.farben.common.utils.poi.ExcelUtil;
import com.farben.system.domain.AgingDesignConfigInfo;
import com.farben.system.domain.vo.GroupVo;
import com.farben.system.mapper.AgingDesignConfigInfoMapper;
import com.farben.system.service.IAgingDesignConfigInfoService;
import com.farben.web.controller.utils.date.DateUtils;
import com.farben.web.controller.utils.excel.ExcelUtils;
import com.farben.web.controller.utils.regex.RegexUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Calendar.SATURDAY;
import static java.util.Calendar.SUNDAY;

@SuppressWarnings("unchecked")
@Api("适老化统计信息")
@RestController
@RequestMapping("/system/aging_design/statistical")
public class AgingDesignStatisticalController extends BaseController {
  private final Logger log = LoggerFactory.getLogger(AgingDesignStatisticalController.class);

  @Autowired
  private ObjectMapper objectMapper;

  @Autowired
  private AgingDesignConfigInfoMapper configInfoMapper;

  @Autowired
  private IAgingDesignConfigInfoService agingDesignConfigInfoService;

  @ApiOperation("查询页面总览配置数据")
  @GetMapping("/queryPageStatistics")
  public AjaxResult queryPageStatistics(@RequestParam("appId") String appId, @RequestParam("sortType") String sortType) {
    AgingDesignConfigInfo all = AgingDesignConfigInfo.builder().appId(appId).build();
    Long allCounts = configInfoMapper.queryCounts(all);
    AgingDesignConfigInfo exemption =
        AgingDesignConfigInfo.builder().appId(appId).exemptionStatus("1").build();
    Long exemptionCounts = configInfoMapper.queryCounts(exemption);
    AgingDesignConfigInfo config =
        AgingDesignConfigInfo.builder().appId(appId).isHaveConfig("1").build();
    Long configCounts = configInfoMapper.queryCounts(config);
    Long unConfigCounts = allCounts - exemptionCounts - configCounts;

    HashMap<String, Object> data = new HashMap<>();
    data.put("pageCounts", allCounts);
    data.put("exemptionCounts", exemptionCounts);
    data.put("configCounts", configCounts);
    data.put("unConfigCounts", unConfigCounts);

    AgingDesignConfigInfo pages = AgingDesignConfigInfo.builder().appId(appId).build();
    List<GroupVo> pageCountsList = configInfoMapper.queryGroups(pages);
    AgingDesignConfigInfo exemptions = AgingDesignConfigInfo.builder().appId(appId).exemptionStatus("1").build();
    List<GroupVo> exemptionList = configInfoMapper.queryGroups(exemptions);
    AgingDesignConfigInfo configs = AgingDesignConfigInfo.builder().appId(appId).isHaveConfig("1").build();
    List<GroupVo> configList = configInfoMapper.queryGroups(configs);
    AgingDesignConfigInfo publish = AgingDesignConfigInfo.builder().appId(appId).publishStatus("2").build();
    List<GroupVo> onlineList = configInfoMapper.queryGroups(publish);

    List<Map<String, Object>> dataList = pageCountsList.stream().filter(g -> StringUtils.isNoneBlank(g.getGroup())).map(groupVo -> {
      Map<String, Object> row = new HashMap<>();
      row.put("businessLine", groupVo.getGroup());
      row.put("pageConts", Optional.ofNullable(pageCountsList.stream().filter(g -> groupVo.getGroup().equals(g.getGroup())).findAny().orElse(new GroupVo()).getCount()).orElse(0L));
      row.put("exemptionCounts", Optional.ofNullable(exemptionList.stream().filter(g -> groupVo.getGroup().equals(g.getGroup())).findAny().orElse(new GroupVo()).getCount()).orElse(0L));
      row.put("configCounts", Optional.ofNullable(configList.stream().filter(g -> groupVo.getGroup().equals(g.getGroup())).findAny().orElse(new GroupVo()).getCount()).orElse(0L));
      row.put("onlineCounts", Optional.ofNullable(onlineList.stream().filter(g -> groupVo.getGroup().equals(g.getGroup())).findAny().orElse(new GroupVo()).getCount()).orElse(0L));
      return row;
    }).collect(Collectors.toList());

    dataList = dataList.stream().sorted(Comparator.comparing(map->-Integer.parseInt(String.valueOf(map.get(sortType.equals("1")?"configCounts":"onlineCounts"))))).collect(Collectors.toList());
    data.put("list",dataList);
    return AjaxResult.success(data);
  }

  @ApiOperation("查询页面配置数据，区分无障碍适老化")
  @GetMapping("/queryPageConfigs")
  public AjaxResult queryPageConfigs(@RequestParam("appId") String appId, @RequestParam("agingDesignType") String agingDesignType) {
    AgingDesignConfigInfo haveConfig = AgingDesignConfigInfo.builder().appId(appId).agingDesignType(agingDesignType).isHaveConfig("1").build();
    Long configCounts = configInfoMapper.queryCounts(haveConfig);

    AgingDesignConfigInfo test = AgingDesignConfigInfo.builder().appId(appId).agingDesignType(agingDesignType).publishStatus("1").build();
    Long testCounts = configInfoMapper.queryCounts(test);

    AgingDesignConfigInfo online = AgingDesignConfigInfo.builder().appId(appId).agingDesignType(agingDesignType).publishStatus("2").build();
    Long onlineCounts = configInfoMapper.queryCounts(online);

    Map<String,Long> data = new HashMap<>();
    data.put("configCounts",configCounts);
    data.put("testCounts",testCounts);
    data.put("onlineCounts",onlineCounts);
    return AjaxResult.success(data);
  }

  @ApiOperation("查询页面新增数据")
  @GetMapping("/queryPageUpConfigs")
  public AjaxResult queryPageUpConfigs(@RequestParam("appId") String appId,@RequestParam("agingDesignType") String agingDesignType, @RequestParam("timeType") Integer timeType){
    Date beginDate = timeType==0?DateUtils.getThisWeekTimeRange().get("begin"):DateUtils.getThisMothTimeRange().get("begin");
    Date endDate = timeType==0?DateUtils.getThisWeekTimeRange().get("end"):DateUtils.getThisMothTimeRange().get("end");
    Date lastBeginDate = timeType==0?DateUtils.getWeekTimeRange(-1).get("begin"):DateUtils.getMonthTimeRange(-1).get("begin");
    Date lastEndDate = timeType==0?DateUtils.getWeekTimeRange(-1).get("end"):DateUtils.getMonthTimeRange(-1).get("end");

    log.info("queryPageUpCounts:beginDate:{},endDate:{},lastBeginDate:{},lastEndDate:{}",beginDate,endDate,lastBeginDate,lastEndDate);
    AgingDesignConfigInfo dto = AgingDesignConfigInfo.builder().appId(appId).agingDesignType(agingDesignType).minTime(lastBeginDate).maxTime(endDate).build();
    List<AgingDesignConfigInfo> dtoList = agingDesignConfigInfoService.selectAgingDesignConfigInfoList(dto);

    List<AgingDesignConfigInfo> beginList = dtoList.stream().filter(d -> d.getCreatedDate().compareTo(beginDate) >= 0 && d.getCreatedDate().compareTo(endDate) <= 0).collect(Collectors.toList());
    List<AgingDesignConfigInfo> endList = dtoList.stream().filter(d -> d.getCreatedDate().compareTo(lastBeginDate) >= 0 && d.getCreatedDate().compareTo(lastEndDate) <= 0).collect(Collectors.toList());
    long configThisCounts = beginList.stream().filter(d -> "1".equals(d.getIsHaveConfig())).count();
    long testThisCounts = beginList.stream().filter(d -> "1".equals(d.getPublishStatus())).count();
    long onlineThisCounts = beginList.stream().filter(d -> "2".equals(d.getPublishStatus())).count();
    long configLastCounts = endList.stream().filter(d -> "1".equals(d.getIsHaveConfig())).count();
    long testLastCounts = endList.stream().filter(d -> "1".equals(d.getPublishStatus())).count();
    long onlineLastCounts = endList.stream().filter(d -> "1".equals(d.getPublishStatus())).count();

    Map<String,Long> data = new HashMap<>();
    data.put("configThisCounts",configThisCounts);
    data.put("configLastCounts",configLastCounts);
    data.put("testThisCounts",testThisCounts);
    data.put("testLastCounts",testLastCounts);
    data.put("onlineThisCounts",onlineThisCounts);
    data.put("onlineLastCounts",onlineLastCounts);
    return AjaxResult.success(data);
  }

  @ApiOperation("查询页面折线数据")
  @GetMapping("/queryPageLineCounts")
  public AjaxResult queryPageLineCounts(@RequestParam("appId") String appId,@RequestParam("agingDesignType") String agingDesignType, @RequestParam("timeType") Integer timeType){
    Map<String,Date> rangeMin = timeType==0?DateUtils.getWeekTimeRange(-5):DateUtils.getMonthTimeRange(-5);
    Map<String,Date> rangeMax = timeType==0?DateUtils.getWeekTimeRange(0):DateUtils.getMonthTimeRange(0);
    Date min = rangeMin.get("begin");
    Date max = rangeMax.get("end");

    AgingDesignConfigInfo dto = AgingDesignConfigInfo.builder().appId(appId).agingDesignType(agingDesignType).isHaveConfig("1").minTime(min).maxTime(max).build();
    List<AgingDesignConfigInfo> dtoList = agingDesignConfigInfoService.selectAgingDesignConfigInfoList(dto);

    Calendar calendar = Calendar.getInstance();
    List<Map<String,Object>> data = new ArrayList<>();
    for (int i = 0; i < 6; i++) {
      Map<String,Date> range = timeType==0?DateUtils.getWeekTimeRange(-i):DateUtils.getMonthTimeRange(-i);
      Date begin = range.get("begin");
      Date end = range.get("end");
      log.info("queryPageLineConfigs:begin:{},end:{}",begin,end);
      dto.setMinTime(begin);
      dto.setMaxTime(end);
      long configCounts = dtoList.stream().filter(d -> d.getCreatedDate().compareTo(begin) >= 0 && d.getCreatedDate().compareTo(end) <= 0).count();
      calendar.setTime(begin);
      String date = calendar.get(Calendar.YEAR) + "(" + (timeType == 0 ? calendar.get(Calendar.WEEK_OF_YEAR) + "周)" : calendar.get(Calendar.MONTH) + 1 + "月)");
      Map<String,Object> map = new HashMap<>();
      map.put("date",date);
      map.put("count",configCounts);
      data.add(map);
    }
    return AjaxResult.success(data);
  }

  @ApiOperation("查询页面历史数据")
  @GetMapping("/queryPageHistoryConfigs")
  public AjaxResult queryPageHistoryConfigs(@RequestParam("appId") String appId,@RequestParam("agingDesignType") String agingDesignType, @RequestParam("timeType") Integer timeType,@RequestParam("beginTime") String beginTime,@RequestParam("endTime") String endTime){
    int yearBegin = RegexUtils.matchPattern(beginTime,"\\d+",1);
    int weekOrMonthBegin = RegexUtils.matchPattern(beginTime, "\\d+", 2);
    int yearEnd = RegexUtils.matchPattern(endTime, "\\d+", 1);
    int weekOrMonthEnd = RegexUtils.matchPattern(endTime, "\\d+", 2);

    AgingDesignConfigInfo dto = AgingDesignConfigInfo.builder().appKey(appId).agingDesignType(agingDesignType)
            .minTime(timeType == 0 ? DateUtils.weekDay(yearBegin, weekOrMonthBegin, SUNDAY) : DateUtils.queryMonthBEDay(yearBegin, weekOrMonthBegin, DateUtils.MIN))
            .maxTime(timeType == 0 ? DateUtils.weekDay(yearEnd, weekOrMonthEnd, SATURDAY) : DateUtils.queryMonthBEDay(yearEnd, weekOrMonthEnd, DateUtils.MAX)).build();
    List<AgingDesignConfigInfo> dtoList = agingDesignConfigInfoService.selectAgingDesignConfigInfoList(dto);

    List<Map<String,Object>> table = new ArrayList<>();
    Date fBegin = timeType==0?DateUtils.weekDay(yearBegin,weekOrMonthBegin,SUNDAY):DateUtils.queryMonthBEDay(yearBegin,weekOrMonthBegin,DateUtils.MIN);
    Date fEnd = timeType==0?DateUtils.weekDay(yearBegin,weekOrMonthBegin,SATURDAY):DateUtils.queryMonthBEDay(yearBegin,weekOrMonthBegin,DateUtils.MAX);
    if (yearBegin==yearEnd){
      table.addAll(doQueryPageHistoryConfigs(dtoList,weekOrMonthEnd-weekOrMonthBegin+1,fBegin,fEnd,yearBegin,weekOrMonthBegin,timeType));
    }
    if (yearEnd-yearBegin>=1){
     // 第一年
      Calendar calendar = Calendar.getInstance();
      int fLimit = (timeType==0?calendar.getWeeksInWeekYear():12)-weekOrMonthBegin+1;
      table.addAll(doQueryPageHistoryConfigs(dtoList,fLimit,fBegin,fEnd,yearBegin,weekOrMonthBegin,timeType));
      // 中间年
      if(yearEnd-yearBegin>1){
        for (int year = yearBegin+1;year<yearEnd;year++){
          int mLimit = timeType==0?calendar.getWeeksInWeekYear():12;
          Date mBegin= timeType==0?DateUtils.firstWeekDay(year,SUNDAY):DateUtils.queryJanuaryBEDay(year,DateUtils.MIN);
          Date mEnd = timeType==0?DateUtils.firstWeekDay(year,SATURDAY):DateUtils.queryJanuaryBEDay(year,DateUtils.MAX);
          table.addAll(doQueryPageHistoryConfigs(dtoList,mLimit,mBegin,mEnd,year,1,timeType));
        }
      }
      // 最后一年
      Date lBegin = timeType==0?DateUtils.firstWeekDay(yearEnd,SUNDAY):DateUtils.queryJanuaryBEDay(yearEnd,DateUtils.MIN);
      Date lEnd = timeType==0?DateUtils.firstWeekDay(yearEnd,SATURDAY):DateUtils.queryJanuaryBEDay(yearEnd,DateUtils.MAX);
      table.addAll(doQueryPageHistoryConfigs(dtoList,weekOrMonthEnd,lBegin,lEnd,yearEnd,1,timeType));
    }
    Map<String,Object> data = new HashMap<>();
    data.put("list",table);
    return AjaxResult.success(data);
  }

  private List<Map<String,Object>> doQueryPageHistoryConfigs(List<AgingDesignConfigInfo> all,long limit,Date begin,Date end,int year,int weekOrMonth,int timeType){
    List<Map<String,Object>> data = new ArrayList<>();
    Stream.iterate(0,i->i=i+1).limit(limit).forEach(i->{
      List<AgingDesignConfigInfo> list = all.stream().filter(vo->{
        Date left = timeType==0?new LocalDate(begin).plusWeeks(i).toDate():new LocalDate(begin).plusMonths(i).toDate();
        Date right = timeType==0?new LocalDate(end).plusWeeks(i).toDate():new LocalDate(end).plusMonths(i).toDate();
        return vo.getCreatedDate().compareTo(left)>=0&&vo.getCreatedDate().compareTo(right)<=0;
      }).collect(Collectors.toList());;
      long configCounts = list.stream().filter(vo->"1".equals(vo.getIsHaveConfig())).count();
      long testCounts= list.stream().filter(vo->"1".equals(vo.getPublishStatus())).count();
      long onlineCounts = list.stream().filter(vo->"2".equals(vo.getPublishStatus())).count();
      Map<String,Object> map = new HashMap<>();
      map.put("time",year+"年第"+(weekOrMonth+i)+(timeType==0?"周":"月"));
      map.put("configCounts",configCounts);
      map.put("testCounts",testCounts);
      map.put("onlineCounts",onlineCounts);
      data.add(map);
    });
    return data;
  }

  @SneakyThrows
  @ApiOperation("导出历史配置数据")
  @GetMapping("/exportPageHistoryConfigs")
  public AjaxResult exportPageHistoryConfigs(HttpServletRequest request,HttpServletResponse response, @RequestParam("appId") String appId, @RequestParam("agingDesignType") String agingDesignType, @RequestParam("timeType") Integer timeType, @RequestParam("beginTime") String beginTime, @RequestParam("endTime") String endTime){
    String realPath = request.getServletContext().getRealPath(this.getClass().getTypeName());
    String pathPrefix = realPath.substring(0, realPath.length() - this.getClass().getTypeName().length());
    List<List<String>> head = Lists.newArrayList(timeType == 0 ? "周" : "月", "配置页面数", "提测页面数", "上线页面数").stream().map(Lists::newArrayList).collect(Collectors.toList());

    List<Map<String,Object>> data = objectMapper.convertValue(((Map<String,Object>)queryPageHistoryConfigs(appId, agingDesignType, timeType, beginTime, endTime).get(AjaxResult.DATA_TAG)).get("list"),List.class);
    List<List<String>> dataList =  data.stream().map(map->{
      LinkedList<String> list = new LinkedList<>();
      list.add(String.valueOf(map.get("time")));
      list.add(String.valueOf(map.get("configCounts")));
      list.add(String.valueOf(map.get("testCounts")));
      list.add(String.valueOf(map.get("onlineCounts")));
      return list;
    }).collect(Collectors.toList());

    ExcelUtils.initExcelFactory(pathPrefix+"data.xlsx",head);
    ExcelUtils.appendDataToExcel(dataList,"页面历史配置情况");
    byte[] bytes = ExcelUtils.getExcelBinaryData();
    ExcelUtils.finish();

    if (bytes.length>0){
      response.setHeader("Content-Disposition","attachment; filename=PageHistoryConfigInfo.xlsx");
      ServletOutputStream os = response.getOutputStream();
      os.write(bytes);
      os.flush();
      os.close();
      return AjaxResult.success(Boolean.TRUE);
    }
    return AjaxResult.error("无历史数据");
  }
}
